package org.ghost.springboot2.demo.controller;

import com.fasterxml.jackson.core.type.TypeReference;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.collections4.CollectionUtils;
import org.ghost.springboot2.demo.common.component.ParameterizedTypeImpl;
import org.ghost.springboot2.demo.dto.RspDTO;
import org.ghost.springboot2.demo.dto.weather.WeatherForecastDTO;
import org.ghost.springboot2.demo.util.GenericMapParaSource;
import org.ghost.springboot2.demo.util.JacksonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.lang.reflect.Type;
import java.util.*;

@RestController
@RequestMapping(value = "demo3")
public class Demo3Controller extends BaseController {
    private final static Logger logger = LoggerFactory.getLogger(Demo3Controller.class);

    @Autowired
    private RedisTemplate<String, String> stringRedisTemplate;

    @ApiOperation(value = "测试set,get,delete字符型", notes = "测试set,get,delete字符型")
    @RequestMapping(value = "test1", method = RequestMethod.POST)
    public RspDTO test1(@RequestParam String key, @RequestParam String value, @RequestParam int second) {
        stringRedisTemplate.opsForValue().set(key, value, second);
        logger.info("获取数据:" + stringRedisTemplate.opsForValue().get(key));

        stringRedisTemplate.delete(key);
        logger.info("delete后获取数据:" + stringRedisTemplate.opsForValue().get(key));

        return this.render();
    }

    @ApiOperation(value = "测试set,get,delete数字型", notes = "测试set,get,delete数字型")
    @RequestMapping(value = "test2", method = RequestMethod.POST)
    public RspDTO test1(@RequestParam String key, @RequestParam Integer value, @RequestParam int second) {
        stringRedisTemplate.opsForValue().set(key, "" + value, second);
        logger.info("获取数据:" + stringRedisTemplate.opsForValue().get(key));

        stringRedisTemplate.delete(key);
        logger.info("delete后获取数据:" + stringRedisTemplate.opsForValue().get(key));

        return this.render();
    }

    @ApiOperation(value = "测试set,get,delete复杂类型", notes = "测试set,get,delete复杂类型")
    @RequestMapping(value = "test3", method = RequestMethod.POST)
    public RspDTO test3(@RequestParam String key, @RequestParam int second) {
        WeatherForecastDTO value = new WeatherForecastDTO() {{
            setPm10(123456);
            setPm25(89);
            setQuality("良好");
            setShiDu("重度");
        }};
        stringRedisTemplate.opsForValue().set(key, JacksonUtil.useDefaultMapper().toJson(value), second);
        logger.info("获取数据:" + stringRedisTemplate.opsForValue().get(key));

        stringRedisTemplate.delete(key);
        logger.info("delete后获取数据:" + stringRedisTemplate.opsForValue().get(key));

        return this.render();
    }

    @ApiOperation(value = "测试set,get,delete复杂List类型", notes = "测试set,get,delete复杂List类型")
    @RequestMapping(value = "test4", method = RequestMethod.POST)
    public RspDTO test4(@RequestParam String key, @RequestParam int second) {
        WeatherForecastDTO value = new WeatherForecastDTO() {{
            setPm10(1256);
            setPm25(20);
            setQuality("优秀");
            setShiDu("轻度");
        }};
        stringRedisTemplate.opsForValue().set(key, JacksonUtil.useDefaultMapper().toJson(Collections.singleton(value)), second);

        String newValue = stringRedisTemplate.opsForValue().get(key);
        logger.info("获取数据:" + newValue);

        stringRedisTemplate.delete(key);
        logger.info("delete后获取数据:" + stringRedisTemplate.opsForValue().get(key));

        return this.render();
    }

    @ApiOperation(value = "测试zset类型", notes = "测试zset类型")
    @RequestMapping(value = "test5", method = RequestMethod.POST)
    public RspDTO test5(@RequestParam String key, @RequestParam int second) {
        stringRedisTemplate.opsForZSet().add(key, "1", 98);
        stringRedisTemplate.opsForZSet().add(key, "2", 65);
        stringRedisTemplate.opsForZSet().add(key, "3", 100);
        stringRedisTemplate.opsForZSet().add(key, "4", 58);
        stringRedisTemplate.opsForZSet().add(key, "5", 75);
        stringRedisTemplate.opsForZSet().add(key, "6", 47);
        stringRedisTemplate.opsForZSet().add(key, "7", 89);
        stringRedisTemplate.opsForZSet().add(key, "8", 77);
        stringRedisTemplate.opsForZSet().add(key, "9", 90);
        stringRedisTemplate.opsForZSet().add(key, "10", 92);
        stringRedisTemplate.opsForZSet().add(key, "11", 95);
        stringRedisTemplate.opsForZSet().add(key, "12", 94);
        stringRedisTemplate.opsForZSet().add(key, "13", 90);

        logger.info("zsetCard->{}", stringRedisTemplate.opsForZSet().zCard(key));
        logger.info("zsetCount[90,100]->{}", stringRedisTemplate.opsForZSet().count(key, 90, 100));
        logger.info("zsetRank[2]->{}", stringRedisTemplate.opsForZSet().rank(key, 2));
        logger.info("zsetRank[3]->{}", stringRedisTemplate.opsForZSet().rank(key, 3));
        Set<String> setUser = stringRedisTemplate.opsForZSet().rangeByScore(key, 60, 80, 0, 2);
        if (CollectionUtils.isNotEmpty(setUser)) {
            logger.info("zsetRangeByScore[60,80,0,2]->{}", setUser.stream().filter(Objects::nonNull).map(String::valueOf).reduce((a, b) -> a + "," + b));
        } else {
            logger.info("zsetRangeByScore[60,80,0,2]->{}", "无数据");
        }

        Set<ZSetOperations.TypedTuple<String>> set = stringRedisTemplate.opsForZSet().rangeByScoreWithScores(key, 90, 100);
        if (CollectionUtils.isNotEmpty(set)) {
            logger.info("zsetRangeByScoreWithScores[90,100]->{}", set.stream().filter(Objects::nonNull).map(it -> it.getValue() + "->" + it.getScore()).reduce((a, b) -> a + ";" + b));
        } else {
            logger.info("zsetRangeByScoreWithScores[90,100]->{}", "无数据");
        }

        stringRedisTemplate.delete(key);
        logger.info("delete后获取数量:" + stringRedisTemplate.opsForZSet().zCard(key));

        return this.render();
    }

    @ApiOperation(value = "测试List<Map<String,Integet>>等超级复杂类型", notes = "测试List<Map<String,Integet>>等超级复杂类型")
    @RequestMapping(value = "test6", method = RequestMethod.POST)
    public RspDTO test6(@RequestParam String key, @RequestParam int second) {
        Type listType = ParameterizedTypeImpl.make(List.class, new Type[]{Long.class}, null);
        Type mapType = ParameterizedTypeImpl.make(Map.class, new Type[]{String.class, listType}, null);

        Map<String, List<Long>> rtnMap = new HashMap<String, List<Long>>();
        rtnMap.put("Hello", Arrays.asList(1L, 254L, 55L));
        rtnMap.put("World", Arrays.asList(110L, 887L, 444L));
        stringRedisTemplate.opsForValue().set(key, JacksonUtil.useDefaultMapper().toJson(rtnMap), second);

        logger.info("Map<String, List<Long>>数据:" + JacksonUtil.useDefaultMapper().fromJson(stringRedisTemplate.opsForValue().get(key), new TypeReference<Map<String, List<Long>>>() {
            @Override
            public Type getType() {
                return mapType;
            }
        }));
        stringRedisTemplate.delete(key);

        logger.info("delete后获取数量:" + stringRedisTemplate.opsForValue().get(key));

        return this.render();
    }

    @ApiOperation(value = "测试mset,mget,msetnx类型", notes = "测试mset,mget,msetnx类型")
    @RequestMapping(value = "test7", method = RequestMethod.POST)
    public RspDTO test7(@RequestParam int second) {
        stringRedisTemplate.opsForValue().multiSet(new GenericMapParaSource("name", "张三").addValue("age", "10").addValue("sex", "男").getValues());

        logger.info("获取数据:" + String.join(",", stringRedisTemplate.opsForValue().multiGet(Arrays.asList("name", "age", "sex"))));

        stringRedisTemplate.opsForValue().multiSetIfAbsent(new GenericMapParaSource("name", "李四").addValue("age", "20").addValue("sex", "男").getValues());
        logger.info("获取数据:" + String.join(",", stringRedisTemplate.opsForValue().multiGet(Arrays.asList("name", "age", "sex"))));

        stringRedisTemplate.delete("name");
        logger.info("删除name字段获取数据:" + String.join(",", stringRedisTemplate.opsForValue().multiGet(Arrays.asList("name", "age", "sex"))));

        stringRedisTemplate.delete("age");
        stringRedisTemplate.delete("sex");
        logger.info("删除age,sex获取数据:" + String.join(",", stringRedisTemplate.opsForValue().multiGet(Arrays.asList("name", "age", "sex"))));

        return this.render();
    }

    @ApiOperation(value = "测试hset,hget,hdel类型", notes = "测试hset,hget,hdel类型")
    @RequestMapping(value = "test8", method = RequestMethod.POST)
    public RspDTO test8(@RequestParam String key, @RequestParam int second) {
        stringRedisTemplate.opsForHash().put(key, "name", "张三");
        stringRedisTemplate.opsForHash().put(key, "age", "10岁");
        stringRedisTemplate.opsForHash().put(key, "sex", "男");

        logger.info("获取数据长度:" + stringRedisTemplate.opsForHash().size(key));
        logger.info("获取数据name:" + stringRedisTemplate.opsForHash().get(key, "name"));
        logger.info("获取数据age:" + stringRedisTemplate.opsForHash().get(key, "age"));
        logger.info("获取数据sex:" + stringRedisTemplate.opsForHash().get(key, "sex"));

        stringRedisTemplate.opsForHash().put(key, "name", "西门吹雪");
        logger.info("获取数据:" + stringRedisTemplate.opsForHash().values(key));
        logger.info("获取数据:" + JacksonUtil.useDefaultMapper().toJson(stringRedisTemplate.opsForHash().entries(key)));

        stringRedisTemplate.opsForHash().delete(key, "name");
        logger.info("删除name字段获取数据:" + JacksonUtil.useDefaultMapper().toJson(stringRedisTemplate.opsForHash().entries(key)));

        stringRedisTemplate.opsForHash().delete(key, "age");
        stringRedisTemplate.opsForHash().delete(key, "sex");
        logger.info("删除age,sex获取数据:" + JacksonUtil.useDefaultMapper().toJson(stringRedisTemplate.opsForHash().entries(key)));

        return this.render();
    }

    @ApiOperation(value = "测试lpush,rpush类型", notes = "测试lpush,rpush类型")
    @RequestMapping(value = "test9", method = RequestMethod.POST)
    public RspDTO test9(@RequestParam String key, @RequestParam int second) {
        stringRedisTemplate.opsForList().leftPushAll(key, Arrays.asList("西门吹雪", "叶孤城", "凌凌漆", "零零发"));
        stringRedisTemplate.opsForList().rightPushAll(key, Arrays.asList("长江", "黄河", "亚马逊河", "尼罗河"));

        logger.info("获取数据长度:" + stringRedisTemplate.opsForList().size(key));
        logger.info("获取数据lrange:" + String.join(",", stringRedisTemplate.opsForList().range(key, 3, 5)));
        logger.info("获取数据lpop:" + stringRedisTemplate.opsForList().leftPop(key));
        logger.info("获取数据rpop:" + stringRedisTemplate.opsForList().rightPop(key));

        stringRedisTemplate.delete(key);
        logger.info("删除后获取数据长度:" + stringRedisTemplate.opsForList().size(key));

        return this.render();
    }

    @ApiOperation(value = "测试members类型", notes = "测试members类型")
    @RequestMapping(value = "test10", method = RequestMethod.POST)
    public RspDTO test10(@RequestParam String key, @RequestParam int second) {
        stringRedisTemplate.opsForSet().add(key, "西门吹雪", "叶孤城", "凌凌漆", "零零发");

        logger.info("获取数据长度:" + stringRedisTemplate.opsForSet().size(key));
        logger.info("获取数据members:" + String.join(",", stringRedisTemplate.opsForSet().members(key)));
        logger.info("获取数据pop:" + stringRedisTemplate.opsForSet().pop(key));
        logger.info("获取数据members:" + String.join(",", stringRedisTemplate.opsForSet().members(key)));

        stringRedisTemplate.delete(key);
        logger.info("删除后获取数据长度:" + stringRedisTemplate.opsForSet().size(key));

        return this.render();
    }

    @ApiOperation(value = "测试distance类型", notes = "测试distance类型")
    @RequestMapping(value = "test11", method = RequestMethod.POST)
    public RspDTO test11(@RequestParam String key, @RequestParam int second) {
        stringRedisTemplate.opsForGeo().add(key, new GenericMapParaSource("西门吹雪", new Point(1, 1)).addValue("叶孤城", new Point(10, 10)).getValues());
        logger.info("获取数据:" + stringRedisTemplate.opsForGeo().hash(key, "西门吹雪", "叶孤城"));
        logger.info("获取数据长度:" + stringRedisTemplate.opsForGeo().distance(key, "西门吹雪", "叶孤城"));

        stringRedisTemplate.delete(key);
        logger.info("删除获取数据:" + stringRedisTemplate.opsForGeo().hash(key, "西门吹雪", "叶孤城"));

        return this.render();
    }

    @ApiOperation(value = "测试distance类型", notes = "测试distance类型")
    @RequestMapping(value = "test12", method = RequestMethod.POST)
    public RspDTO test13(@RequestParam String key, @RequestParam int second) {
        stringRedisTemplate.opsForHyperLogLog().add(key, "西门吹雪", "叶孤城", "凌凌漆", "零零发");
        stringRedisTemplate.opsForHyperLogLog().add(key, "西门吹雪", "张三", "李四", "王五");
        logger.info("获取数据长度:" + stringRedisTemplate.opsForHyperLogLog().size(key));

        stringRedisTemplate.delete(key);
        logger.info("删除获取数据长度:" + stringRedisTemplate.opsForHyperLogLog().size(key));

        return this.render();
    }
}
